package com.orange.lswidget.widgets.musicplayer;

import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.IBinder;
import android.view.View;
import android.widget.RemoteViews;

import com.orange.lswidget.LSWidgetManager;
import com.orange.lswidget.R;
import com.orange.lswidget.widgets.musicplayer.entry.MusicPlayer;
import com.orange.lswidget.widgets.musicplayer.entry.TrackInfo;
import com.orange.lswidget.widgets.musicplayer.service.IMusicPlayerService;
import com.orange.util.LogHelper;
import com.orange.util.MusicPreferences;
import com.orange.util.MusicUtils;

public final class MusicPlayerClient {
	private static final String			TAG					= "MusicPlayerClient";

	private static final String			UNKNOWN				= "<unknown>";
	private static final String			METHOD_SETENABLED	= "setEnabled";
	private static final int			MODE_ALWAYS_SHOW	= 1;
	private static final int			MODE_AUTO_HIDE		= 0;
	private static Object				sObject				= new Object();

	private static PlaybackStatus		sStatus				= PlaybackStatus.STOP;
	private static IMusicPlayerService	sMpService;

	private  boolean						mIsMusicSlatOpened	= false;
	private boolean						mPlaybackComplete;
	private boolean						mIsHeadsetPlugged	= false;

	private MusicPlayer					mMp;
	private Context						mContext;

	/**
	 * modify by gaoge ,because if not single instance,the property mIsMusicSlatOpened would be incorrect
	 * ,but after full test,single instance would cause another problem,which is when reboot the handset
	 * and the music is playing,the LockscreenView can't show the Music panel
	 */
//	private static MusicPlayerClient instance;
//	public static MusicPlayerClient getInstance(Context context, IBinder service){
//		if(null == instance){
//			instance = new MusicPlayerClient(context,service);
//		}
//		return instance;
//	}
	public MusicPlayerClient(Context context, IBinder service) {
		MusicPlayerManager manager = MusicPlayerManager.getInstance(context);

		mContext = context;
		sMpService = manager.createMpService(service);
		mMp = manager.createMusicPlayer();
	}

	/**
	 * add by gaoge ,to save the oldStatus to SharedPreference
	 */
	private void saveOldStatusToSharedPreference(){
		if(PlaybackStatus.PLAYING == sStatus){
			MusicPreferences.setMusicPlayOldStatus(mContext, MusicPreferences.MUSIC_OLD_STATUS_PLAYING);
		}else if(PlaybackStatus.PAUSE == sStatus){
			MusicPreferences.setMusicPlayOldStatus(mContext, MusicPreferences.MUSIC_OLD_STATUS_PAUSE);
		}else if(PlaybackStatus.STOP == sStatus){
			MusicPreferences.setMusicPlayOldStatus(mContext, MusicPreferences.MUSIC_OLD_STATUS_STOP);
		}
	}
	private PlaybackStatus getOldStatusFromSharedPreference(){
		PlaybackStatus oldStatus = null;
		String str_oldStatus = MusicPreferences.getMusicPlayOldStatus(mContext);
		if( MusicPreferences.MUSIC_OLD_STATUS_PLAYING.equals(str_oldStatus)){
			oldStatus = PlaybackStatus.PLAYING;
		}else if( MusicPreferences.MUSIC_OLD_STATUS_PAUSE.equals(str_oldStatus)){
			oldStatus = PlaybackStatus.PAUSE;
		}else if( MusicPreferences.MUSIC_OLD_STATUS_STOP.equals(str_oldStatus)){
			oldStatus = PlaybackStatus.STOP;
		}
		return oldStatus;
		
	}
	
	/**
	 * This method is used to change the Music Panel in Lockscreen after receive actions,
	 * such as Music actions,Lockscreen actions and so on
	 * @param autoHide
	 *            true indicates auto-hide, false indicates always-show.
	 */
	public void updateMusicSlatStatus() {
		LogHelper.i("loop", "updateMusicPlayerStatus. [mMPService=" + sMpService);

		if (sMpService != null) {
			PlaybackStatus oldStatus = getOldStatusFromSharedPreference();
			boolean playing = sMpService.isPlaying();
			/**
			 * add by gaoge 2011-07-21,to fix the bug that system always send
			 * action com.android.music.queuechanged
			 */
			TrackInfo mTrackInfo = getTrackInfo();

			synchronized (sStatus) {
//				PlaybackStatus oldStatus = sStatus;
				
				sStatus = (playing ? PlaybackStatus.PLAYING : PlaybackStatus.PAUSE);
				if (mTrackInfo.mAudioId < 0) {
					sStatus = PlaybackStatus.STOP;
				}

				if (isPlaybackCompleteStatus() && playing) {
					sStatus = PlaybackStatus.PAUSE;
					setPlaybackCompleteStatus(false);
				}
				saveOldStatusToSharedPreference();
				LogHelper.v("chunlei", "updateMusicSlatStatus(). Thread.name " + Thread.currentThread().getName() + ",nowStatus:" + sStatus
						+ ", oldStatus:" + oldStatus + ", playing" + ":"
						+ playing + " ,headsetPlug: " + mIsHeadsetPlugged);

				performUpdate(mTrackInfo, mIsHeadsetPlugged, oldStatus, sStatus);
			}
		} else {
			LogHelper.w(TAG, "onServiceDisconnected. mMPService is null!");
		}
	}

	/**
	 * 
	 * @param ti
	 * @param isHeadsetPlugged is headset plugged
	 * @param oldStatus identify the oldStatus of the music player maybe PlAYING,PAUSE,STOP
	 * @param nowStatus identify the current status of the music player maybe PlAYING,PAUSE,STOP
	 */
	public void performUpdate(TrackInfo ti, Boolean isHeadsetPlugged,
			PlaybackStatus oldStatus, PlaybackStatus nowStatus) {
		LogHelper.i("loop", "performUpdate()");
		boolean hasContent = showPanel(mContext, isHeadsetPlugged, oldStatus,
				nowStatus);

		if (hasContent) {
			LogHelper.v(TAG, "performUpdate. artistName: " + ti.mArtistName
					+ " ,albumName: " + ti.mAlbumName + " ,trackName: "
					+ ti.mTrackName);
			RemoteViews views = getAppWidgetWithEvents(mContext,
					ti.mArtistName, ti.mAlbumName, ti.mTrackName, ti.mAlbumId,
					nowStatus);
			updateWidgets(MusicLSWidgetProvider.MY_COMPONENT_NAME, views, true);
			LogHelper.i(TAG, "hasContent true, getAppWidgetWithEvents");
		} else {
			RemoteViews views = getAppWidgetWithNoEvents(mContext);
			updateWidgets(MusicLSWidgetProvider.MY_COMPONENT_NAME, views, false);
			LogHelper.i(TAG, "hasContent false, getAppWidgetWithNoEvents");
		}
	}

	/**
	 * 
	 * @param status whether the music play completed or not
	 */
	public void setPlaybackCompleteStatus(boolean status) {
		synchronized (sObject) {
			mPlaybackComplete = status;
		}
	}

	public boolean isPlaybackCompleteStatus() {
		return mPlaybackComplete;
	}

	/**
	 * update the Music AppWidgetProvider in LockscreenView
	 * @param provider
	 * @param views the views contains the new state
	 * @param hasContent if the Music Control panel has content
	 */
	private void updateWidgets(ComponentName provider, RemoteViews views,
			boolean hasContent) {
		LogHelper.i("loop", "updateWidgets()");
		LogHelper.d(TAG, "^^^^^^ mHasContent: " + hasContent + " ^^^^^^^");

		LSWidgetManager.updateLSWidgetProvider(provider, views, hasContent);
	}

	public RemoteViews getAppWidgetWithNoEvents(Context context) {
		RemoteViews views = new RemoteViews(context.getPackageName(),
				R.layout.layout_view_music_player_empty);
		return views;
	}

	private RemoteViews getAppWidgetWithEvents(Context context, String artist,
			String album, String track, long albumId, PlaybackStatus status) {
		LogHelper.d(TAG, "getAppWidgetWithEvents. albumId: " + albumId);
		RemoteViews views = new RemoteViews(context.getPackageName(),
				R.layout.layout_view_music_player);

		setMusicAlbumPic(context, albumId, views);
		setPlayStatusVisibility(context, albumId, views);
		setMusicTextInfo(context, artist, album, albumId, track, views);

		MusicUtils.updateMusicTrackSelected(context,
				(albumId >= 0) ? "true" : "false");

		// if devices connected bluetooth successfully. music slat should
		// appear.
		if (albumId < 0) {
			LogHelper.d(TAG, "getAppWidgetWithEvents. setBroadcastFromBT");
			MusicPreferences.setBroadcastFromBT(context, true);
		}

		setMusicBtnEventReceiver(context, views);
		setMusicBtnEventEnabled(views, albumId);
		setMusicBtnImageView(status, views);

		return views;
	}

	/**
	 * Set event receiver for music
	 */
	private void setMusicBtnEventReceiver(Context context, RemoteViews views) {
		views.setOnClickPendingIntent(R.id.pnl_mp_btn_play_stop,
				getPlayPausePendingIntent(context));
		views.setOnClickPendingIntent(R.id.pnl_mp_btn_prev,
				getPrevPendingIntent(context));
		views.setOnClickPendingIntent(R.id.pnl_mp_btn_next,
				getNextPendingIntent(context));
	}

	private PendingIntent getPlayPausePendingIntent(Context context) {
		Intent launchIntent = new Intent(mMp.getTogglepauseAction());
		return PendingIntent.getBroadcast(context, 0 /* no requestCode */,
				launchIntent, 0 /* no flags */);
	}

	private PendingIntent getNextPendingIntent(Context context) {
		Intent launchIntent = new Intent(mMp.getNextAction());
		launchIntent.setComponent(mMp.getMpComponentName());
		return PendingIntent.getService(context, 0 /* no requestCode */,
				launchIntent, 0 /* no flags */);
	}

	private PendingIntent getPrevPendingIntent(Context context) {
		Intent launchIntent = new Intent(mMp.getPreviousAction());
		launchIntent.setComponent(mMp.getMpComponentName());
		return PendingIntent.getService(context, 0 /* no requestCode */,
				launchIntent, 0 /* no flags */);
	}

	private void setMusicBtnEventEnabled(RemoteViews views, long albumId) {
		if (albumId >= 0) {
			views.setBoolean(R.id.pnl_mp_btn_play_stop, METHOD_SETENABLED, true);
			views.setBoolean(R.id.pnl_mp_btn_prev, METHOD_SETENABLED, true);
			views.setBoolean(R.id.pnl_mp_btn_next, METHOD_SETENABLED, true);
		} else {
			views.setBoolean(R.id.pnl_mp_btn_play_stop, METHOD_SETENABLED,
					false);
			views.setBoolean(R.id.pnl_mp_btn_prev, METHOD_SETENABLED, false);
			views.setBoolean(R.id.pnl_mp_btn_next, METHOD_SETENABLED, false);

			views.setImageViewResource(R.id.pnl_mp_btn_play_stop,
					R.drawable.music_ic_play_notrack);
			views.setImageViewResource(R.id.pnl_mp_btn_prev,
					R.drawable.music_ic_pre_notrack);
			views.setImageViewResource(R.id.pnl_mp_btn_next,
					R.drawable.music_ic_next_notrack);
		}
	}

	/**
	 * Set music player button image view for pause, stop or playing
	 */
	private void setMusicBtnImageView(PlaybackStatus status, RemoteViews views) {
		switch (status) {
		case PLAYING:
			views.setImageViewResource(R.id.mp_playing_status,
					R.drawable.music_ic_lock_play);
			views.setImageViewResource(R.id.pnl_mp_btn_play_stop,
					R.drawable.music_ic_pause);
			break;
		case STOP:
		case PAUSE:
			long albumId = sMpService.getAlbumId();
			if (albumId >= 0) {
				views.setImageViewResource(R.id.mp_playing_status,
						R.drawable.music_ic_lock_pause);

				views.setImageViewResource(R.id.pnl_mp_btn_play_stop,
						R.drawable.music_ic_play);
				views.setImageViewResource(R.id.pnl_mp_btn_prev,
						R.drawable.music_ic_pre);
				views.setImageViewResource(R.id.pnl_mp_btn_next,
						R.drawable.music_ic_next);
			}
			break;
		default:
			break;
		}
	}

	/**
	 * Set track. artist .album name.
	 */
	private void setMusicTextInfo(Context context, String artist, String album,
			long albumId, String track, RemoteViews views) {
		String trackName = "";
		String artistName = "";
		String albumName = "";
		if (albumId >= 0) {
			trackName = (track == null ? context
					.getString(R.string.widget_music_player_track_unknown) : track);
			if (artist == null || UNKNOWN.equals(artist)) {
				artistName = context
						.getString(R.string.widget_music_player_artist_unknown);
			} else {
				artistName = artist;
			}
			// artistName = (artist == null ? context
			// .getString(R.string.widget_music_player_artist_unknown)
			// : artist);
			albumName = (album == null ? context
					.getString(R.string.widget_music_player_album_unknown) : album);
		} else {
			trackName = context
					.getString(R.string.widget_music_player_no_track);
			// artistName = context
			// .getString(R.string.widget_music_player_no_artist);
			// albumName = context
			// .getString(R.string.widget_music_player_no_album);
		}

		views.setTextViewText(R.id.pnl_mp_track_name, trackName);
		views.setTextViewText(R.id.pnl_mp_track_artist, artistName);
		views.setTextViewText(R.id.pnl_mp_track_album, albumName);
	}

	private void setPlayStatusVisibility(Context context, long albumId,
			RemoteViews views) {
		if (albumId < 0) {
			views.setViewVisibility(R.id.mp_playing_status, View.GONE);
		} else {
			boolean isSelected = MusicUtils.isMusicTrackSelected(context);
			boolean fromBT = MusicPreferences.isBroadcastFromBT(context);
			LogHelper.i(TAG,
					"setPlayStatusVisibility. albumId > 0 mIsMusicSlatOpened: "
							+ isMusicSlatOpened() + " isSelected: " + isSelected
							+ " fromBT: " + fromBT);

			if (isSelected && fromBT) { // no track and from bluetooth
				MusicPreferences.setBroadcastFromBT(context, false);
				if (isMusicSlatOpened()) {
					views.setViewVisibility(R.id.mp_playing_status, View.GONE);
				} else {
					views.setViewVisibility(R.id.mp_playing_status,
							View.VISIBLE);
				}
			}

		}
	}

//	Object mLock = new Object();
//	public synchronized void setMusicSlatOpened(boolean isOpened) {
//		synchronized(mLock){
//			LogHelper.d("chunlei","^^^^^^^^^^^^^^^^^^^^^^^^^^^ setMusicSlatOpened(): isOpened: " + isOpened);
//			mIsMusicSlatOpened = isOpened;
//		}
//	}
//
//	public synchronized boolean isMusicSlatOpened() {
//		synchronized(mLock){
//			LogHelper.d("chunlei","%%%%%%%%%%%%%%%%%%%%%%% isMusicSlatOpened(): isOpened: " + mIsMusicSlatOpened);
//			return mIsMusicSlatOpened;
//		}
//	}
	
	/**
	 * add  by gaoge 2011-12-25,because the MusicPlayerClient is not single instance,the
	 * mIsMusicSlatOpened would be not always correct
	 */
	public synchronized void setMusicSlatOpened(boolean isOpened) {
		saveMusicSlatOpenedSharedPreference(isOpened);
	}

	/**
	 * 
	 * @return if the Music Control panel is opened
	 */
	public synchronized boolean isMusicSlatOpened() {
		return getMusicSlatOpenedFromSharedPreference();
	}
	
	/**
	 * set the value of whether the Music control panel is opened to SharedPreference
	 * @param isOpened
	 */
	private void saveMusicSlatOpenedSharedPreference(boolean isOpened){
		MusicPreferences.setMusicSlatOpened(mContext, isOpened);
	}
	/**
	 * get the value of whether the Music control panel is opened  from SharedPreference
	 * @return
	 */
	private boolean getMusicSlatOpenedFromSharedPreference(){
		return MusicPreferences.getMusicSlatOpened(mContext);
		
	}

	private Bitmap getAlbumPicture(Context context, long albumId) {
		return MusicUtils.getArtwork(context, albumId);
	}

	/**
	 * Set album picture.
	 */
	private void setMusicAlbumPic(Context context, long albumId,
			RemoteViews views) {
		try {
			Bitmap albumPic = getAlbumPicture(context, albumId);
			views.setImageViewBitmap(R.id.pnl_mp_album_cover, albumPic);
		} catch (Exception e) {
			LogHelper.e(TAG, "setMusicAlbumPic. ", e);
		}
	}

	private static final int	LOCKSCREEN_LOAD	= 1;
	private static final int	LOCKSCREEN_QUIT	= 0;

	/**
	 * This method returns whether shuold show the Music control Panel in LockscreenView
	 * @param context
	 * @param isHeadsetPluged identify the oldStatus of the music player maybe PlAYING,PAUSE,STOP
	 * @param oldStatus identify the oldStatus of the music player maybe PlAYING,PAUSE,STOP
	 * @param nowStatus identify the current status of the music player maybe PlAYING,PAUSE,STOP
	 * @return
	 */
	private boolean showPanel(Context context, boolean isHeadsetPluged,
			PlaybackStatus oldStatus, PlaybackStatus nowStatus) {

		boolean isShow = false;
		if (isHeadsetPluged) {
			LogHelper.d(TAG, "showPanel. headsetPluged");
			isShow = true;
		} else {
			int showMode = MusicUtils.getShowMusicSetting(context);
			switch (showMode) {
			case MODE_ALWAYS_SHOW:
				LogHelper.d(TAG, "showPanel. always show");
				isShow = true;
				break;
			case MODE_AUTO_HIDE:
				if (nowStatus == PlaybackStatus.PLAYING) {
					LogHelper.d(TAG, "showPanel. playing");
					isShow = true;
				} else {
					LogHelper.d(TAG, "showPanel. isLockscreenRunning: "
							+ isLockscreenRunning() + " ,isMusicSlatOpened: "
							+ isMusicSlatOpened());
					// if (isLockscreenRunning() /*&& isMusicSlatOpened()*/) {
					// LogHelper.d(TAG, "showPanel. pause 1");
					// isShow = true;
					// } else {
					// LogHelper.d(TAG, "showPanel. pause 2");
					// isShow = false;
					// }

					LogHelper.d("chunlei", "%%%%%%%%%%%%%%%%%%%%%%%%%%% mIsMusicSlatOpened: " + isMusicSlatOpened());
					//modify by gaoge 2011-12-23,for fix bug 0014257,when isMusicSlatOpened true,the isShow will always true
					if (isLockscreenRunning()
							&& oldStatus == PlaybackStatus.PLAYING
							&& nowStatus == PlaybackStatus.PAUSE || isMusicSlatOpened() ) {
						isShow = true;
					} else {
						isShow = false;
					}
				}
				break;
			default:
				break;
			}
		}

		return isShow;
	}

	private boolean isLockscreenRunning() {
		boolean isRun = false;
		int status = MusicPreferences.getLockScreenStatus(mContext);

		if (status == LOCKSCREEN_LOAD) {
			isRun = true;
		} else if (status == LOCKSCREEN_QUIT) {
			isRun = false;
		}
		return isRun;
	}

	public void setHeadsetPlugged(boolean isPluged) {
		mIsHeadsetPlugged = isPluged;
	}

	private TrackInfo getTrackInfo() {
		LogHelper.i("loop", "getTrackInfo()");
		TrackInfo info = null;

		String track = null;
		String album = null;
		long albumId = -1;
		String artist = null;
		long duration = 0;
		long position = 0;
		long audioId = -1;

		track = sMpService.getTrackName();
		album = sMpService.getAlbumName();
		albumId = sMpService.getAlbumId();
		/**
		 * this two methods will cause system to send
		 * com.android.music.queuechanged action every time.add by gaoge
		 * 2011-07-21
		 */
		artist = sMpService.getArtistName();
		audioId = sMpService.getAudioId();
		duration = 0;
		position = 0;

		LogHelper.v(TAG, "getTrackInfo. ===track: " + track + "===album: "
				+ album + "====albumId: " + albumId + "===artist: " + artist
				+ "===audioId: " + audioId);

		info = new TrackInfo(audioId, track, album, albumId, artist, position,
				duration);

		return info;
	}

	public static enum PlaybackStatus {
		PLAYING, STOP, PAUSE,
	}

	/**
	 * return the current system's MediaPlaybackService
	 * @return
	 */
	public static IMusicPlayerService getSystemMPService() {
		return sMpService;
	}
}
